import createApp from './app';

const { app, router, store } = createApp();

// 预取数据方法
const preGetData = async (matchedComponent, to) => {
  try {
    if (matchedComponent.asyncData) {
      await matchedComponent.asyncData({ store, route: to });
      window.__INITIAL_STATE__ = { ...store.state }; // 客户端预取到数据后，将store数据赋值给window.__INITIAL_STATE__
    }
  } catch (err) { //  某一个请求异常了，也resolve
    console.log('component asyncData err.', err);
    return { returnCode: '-99999' };
  }
};

console.log('window.__INITIAL_STATE__', window.__INITIAL_STATE__);
// 同步store
// console.log('entry window.__INITIAL_STATE__', window.__INITIAL_STATE__);
// 如果服务端预取到asyncData的数据了，同步store
if (window.__INITIAL_STATE__) {
  store.replaceState(window.__INITIAL_STATE__);
} else {
  // 降级时, 客户端执行asyncData
  router.afterEach((to, from) => {
    const matchedComponents = router.getMatchedComponents(to);
    console.log('afterEach window.__INITIAL_STATE__', window.__INITIAL_STATE__);
    if (window.__INITIAL_STATE__) { // 客户端数据预取到了，页面切换时，由beforeResolve执行asyncData
      return;
    }
    Promise.all(matchedComponents.map(c => {
      preGetData(c, to);
    }));
  });
}

// 在挂载 app 之前调用 router.onReady，因为路由器必须要提前解析路由配置中的异步组件，才能正确地调用组件中可能存在的路由钩子
router.onReady(() => {
  // 客户端数据预取逻辑
  // 参考：https://ssr.vuejs.org/zh/guide/data.html#%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%95%B0%E6%8D%AE%E9%A2%84%E5%8F%96-client-data-fetching
  // 添加路由钩子函数，用于处理 asyncData.
  // 在初始路由 resolve 后执行，
  // 以便我们不会二次预取(double-fetch)已有的数据。
  // 使用 `router.beforeResolve()`，以便确保所有异步组件都 resolve。
  router.beforeResolve((to, from, next) => {
    const matched = router.getMatchedComponents(to);
    const prevMatched = router.getMatchedComponents(from);
    // 我们只关心非预渲染的组件
    // 所以我们对比它们，找出两个匹配列表的差异组件
    let diffed = false;
    const activated = matched.filter((c, i) => {
      return diffed || (diffed = (prevMatched[i] !== c));
    });

    if (!activated.length) {
      return next();
    }

    // 这里如果有加载指示器 (loading indicator)，就触发
    Promise.all(activated.map(c => {
      return preGetData(c);
    })).then(() => {
      // 停止加载指示器(loading indicator)
      next();
    }).catch(next);
  });

  app.$mount('#app');
});